﻿using System;
using System.Collections.Generic;
using System.Text;
using DarkAngels.WoW.Library.Interfaces;
using System.Xml;

namespace DarkAngels.WoW.Library.Armory.Character.tabs
{
    public class ReputationTab : AbstractDataClass
    {
        private const string XPATH_REPUTATION_FACTION_GROUPS = "/page/characterInfo/reputationTab/faction";
        private const string XPATH_CHARACTER_BASIC_INFO_NODE = "/page/characterInfo/character";

        private Character m_char = null;
        public Character Character
        {
            get
            {
                return m_char;
            }
        }
        public ReputationTab(Character character)
        {
            m_char = character;
        }
        public List<Faction> Factions
        {
            get;
            private set;
        }
        private int sum = -1;
        public int NumberOfFactions
        {
            get
            {
                if (sum == -1)
                {
                    sum = 0;
                    foreach (Faction f in Factions)
                        sum += f.SubFactions;
                }
                return sum;
            }
        }

        #region DataTab Members

        public override void Load()
        {
            LoadData();
        }
        private void LoadData()
        {
            XmlData = Character.Provider.GetFile(BuildUri(FileName));
            XmlDocument xmlDoc = new XmlDocument();
            xmlDoc.LoadXml(XmlData);
            this.Factions = RecurseItem(xmlDoc.SelectNodes(XPATH_REPUTATION_FACTION_GROUPS));

            if (!Character._Loaded)
            {
                XmlNode characterInfo = xmlDoc.SelectSingleNode(XPATH_CHARACTER_BASIC_INFO_NODE);
                Character._SetProperties(characterInfo);
            }
        }
        private String FileName
        {
            get
            {
                if (Character._Loaded)
                    return String.Format("character-reputation.xml?{0}", Character.CharUrl);
                else
                    return String.Format("character-reputation.xml?r={0}&n={1}", Character.RealmName, Character.CharacterName);
            }
        }
        private String XmlData
        {
            get;
            set;
        }

        private List<Faction> RecurseItem(XmlNodeList list)
        {
            List<Faction> categories = new List<Faction>();
            foreach (XmlNode node in list)
            {
                Faction curr = new Faction();
                if (node.Attributes["header"] != null)
                {
                    curr.Factions = RecurseItem(node.SelectNodes("./faction")).ToArray();
                    curr.IsHeader = true;
                }
                curr.Key = node.Attributes["key"].Value;
                curr.Name = node.Attributes["name"].Value;
                if (node.Attributes["reputation"] != null)
                    curr.Reputation = Int32.Parse(node.Attributes["reputation"].Value);
                categories.Add(curr);
            }
            return categories;
        }

        #endregion

        public Faction GetFaction(String key)
        {
            foreach (Faction fc in Factions)
            {
                if (fc.Key.Equals(key))
                    return fc;
                if (fc.IsHeader)
                {
                    Faction f = fc.GetFaction(key);
                    if (!f.Equals(Faction.NULL_FACTION))
                        return f;
                }
            }
            return Faction.NULL_FACTION;
        }
    }

    public struct FactionCategory
    {
        public String Name
        {
            get;
            internal set;
        }
        public String Key
        {
            get;
            internal set;
        }
        public List<Faction> Factions
        {
            get;
            internal set;
        }
    }
    public struct Faction
    {
        public static Faction NULL_FACTION = new Faction();
        public String Name
        {
            get;
            internal set;
        }
        public bool IsHeader
        {
            get;
            internal set;
        }
        public Faction[] Factions
        {
            get;
            internal set;
        }
        public String Key
        {
            get;
            internal set;
        }
        public Int32 Reputation
        {
            get;
            internal set;
        }
        public ReputationLevel ReputationLevel
        {
            get
            {
                if (Reputation >= 42000)
                    return ReputationLevel.Exalted;
                else if (Reputation >= 21000)
                    return ReputationLevel.Revered;
                else if (Reputation >= 9000)
                    return ReputationLevel.Honored;
                else if (Reputation >= 3000)
                    return ReputationLevel.Friendly;
                else if (Reputation >= 0)
                    return ReputationLevel.Neutral;
                else if (Reputation >= -3000)
                    return ReputationLevel.Honored;
                else
                    return ReputationLevel.Hated;
            }
        }

        public Faction GetFaction(String key)
        {
            foreach (Faction fc in Factions)
            {
                if (fc.Key.Equals(key))
                    return fc;
                if (fc.IsHeader)
                {
                    Faction f = fc.GetFaction(key);
                }
            }
            return Faction.NULL_FACTION;
        }

        public int SubFactions
        {
            get
            {
                int sum = 1; //count the current one
                if (IsHeader)
                {
                    foreach (Faction f in Factions)
                    {
                        sum += f.SubFactions;
                    }
                }
                return sum;
            }
        }
    }
}
